<template>
  <div class="tags-view-container">
    <scroll-pane class="tags-view-wrapper" :tag-refs="tagRefs">
      <router-link
        ref="tagRefs"
        v-for="tag in tagsViewStore.visitedViews"
        :key="tag.path"
        :class="{ active: isActive(tag) }"
        class="tags-view-item"
        :to="{ path: tag.path, query: tag.query }"
        @contextmenu.prevent="openMenu(tag, $event)"
      >
        {{ tag.meta?.title }}
        <el-icon
          v-if="!isAffix(tag)"
          :size="12"
          @click.prevent.stop="closeSelectedTag(tag)"
        >
          <Close />
        </el-icon>
      </router-link>
    </scroll-pane>
    <ul
      v-show="visible"
      class="contextmenu"
      :style="{ left: left + 'px', top: top + 'px' }"
    >
      <li @click="refreshSelectedTag(selectedTag)">刷新</li>
      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
        关闭
      </li>
      <li @click="closeOthersTags">关闭其它</li>
      <li @click="closeAllTags(selectedTag)">关闭所有</li>
    </ul>
  </div>
</template>

<script lang="ts">
import { getCurrentInstance, onMounted, ref, watch } from "vue";
import { RouterLink, useRoute, useRouter } from "vue-router";
import { type TagView, useTagsViewStore } from "@/store/modules/tags-view";
import scrollPane from "./scrollPane.vue";
import path from "path-browserify";
import { constantRoutes } from '../../../router/index'

export default {
  components: {
    scrollPane,
  },
  setup() {
    /** 标签页组件元素的引用数组 */
    const tagRefs = ref<InstanceType<typeof RouterLink>[]>([]);
    const instance = getCurrentInstance();
    const router = useRouter();
    const route = useRoute();
    const tagsViewStore = useTagsViewStore();
    /** 右键菜单的状态 */
    const visible = ref(false);
    /** 右键菜单的 top 位置 */
    const top = ref(0);
    /** 右键菜单的 left 位置 */
    const left = ref(0);
    /** 当前正在右键操作的标签页 */
    const selectedTag = ref<TagView>({});
    /** 固定的标签页 */
    let affixTags: any = [];

    /** 判断标签页是否激活 */
    const isActive = (tag: TagView) => {
      return tag.path === route.path;
    };

    /** 判断标签页是否固定 */
    const isAffix = (tag: TagView) => {
      return tag.meta?.affix;
    };

    /** 筛选出固定标签页 */
    const filterAffixTags = (routes: any, basePath = "/") => {
      const tags: TagView[] = [];
      routes.forEach((route: any) => {
        if (isAffix(route)) {
          const tagPath = path.resolve(basePath, route.path);
          tags.push({
            fullPath: tagPath,
            path: tagPath,
            meta: { ...route.meta },
          });
        }
        if (route.children) {
          const childTags = filterAffixTags(route.children, route.path);
          tags.push(...childTags);
        }
      });
      return tags;
    };

    /** 跳转到最后一个标签页 */
    const toLastView = (visitedViews: TagView[], view: TagView) => {
      const latestView = visitedViews.slice(-1)[0];
      const fullPath = latestView?.fullPath;
      if (fullPath !== undefined) {
        router.push(fullPath);
      } else {
        // 如果 TagsView 全部被关闭了，则默认重定向到主页
        if (view.name === "Dashboard") {
          // 重新加载主页
          router.push({ path: "/redirect" + view.path, query: view.query });
        } else {
          router.push("/");
        }
      }
    };

    /** 初始化标签页 */
    const initTags = () => {
      affixTags = filterAffixTags(constantRoutes);
      for (const tag of affixTags) {
        // 必须含有 name 属性
        tag.meta?.title && tagsViewStore.addVisitedView(tag);
      }
    };

    /** 关闭当前正在右键操作的标签页 */
    const closeSelectedTag = (view: TagView) => {
      tagsViewStore.delVisitedView(view);
      tagsViewStore.delCachedView(view);
      isActive(view) && toLastView(tagsViewStore.visitedViews, view);
    };

    /** 刷新当前正在右键操作的标签页 */
    const refreshSelectedTag = (view: TagView) => {
      tagsViewStore.delCachedView(view);
      router.replace({ path: "/redirect" + view.path, query: view.query });
    };

    /** 关闭其他标签页 */
    const closeOthersTags = () => {
      const fullPath = selectedTag.value.fullPath;
      if (fullPath !== route.path && fullPath !== undefined) {
        router.push(fullPath);
      }
      tagsViewStore.delOthersVisitedViews(selectedTag.value);
      tagsViewStore.delOthersCachedViews(selectedTag.value);
    };

    /** 关闭所有标签页 */
    const closeAllTags = (view: TagView) => {
      tagsViewStore.delAllVisitedViews();
      tagsViewStore.delAllCachedViews();
      if (affixTags.some((tag: any) => tag.path === route.path)) return;
      toLastView(tagsViewStore.visitedViews, view);
    };

    /** 打开右键菜单面板 */
    const openMenu = (tag: TagView, e: MouseEvent) => {
      const menuMinWidth = 105;
      // 当前组件距离浏览器左端的距离
      const offsetLeft = instance!.proxy!.$el.getBoundingClientRect().left;
      // 当前组件宽度
      const offsetWidth = instance!.proxy!.$el.offsetWidth;
      // 面板的最大左边距
      const maxLeft = offsetWidth - menuMinWidth;
      // 面板距离鼠标指针的距离
      const left15 = e.clientX - offsetLeft + 15;
      left.value = left15 > maxLeft ? maxLeft : left15;
      top.value = e.clientY;
      // 显示面板
      visible.value = true;
      // 更新当前正在右键操作的标签页
      selectedTag.value = tag;
    };

    /** 关闭右键菜单面板 */
    const closeMenu = () => {
      visible.value = false;
    };

    /** 添加标签页 */
    const addTags = () => {
      if (route.meta?.title) {
        tagsViewStore.addVisitedView(route)
        tagsViewStore.addCachedView(route)
      }
    };

    watch(
      route,
      () => {
        addTags();
      },
      {
        deep: true,
      }
    );

    onMounted(() => {
      initTags();
      addTags();
    });

    watch(visible, (value) => {
      value
        ? document.body.addEventListener("click", closeMenu)
        : document.body.removeEventListener("click", closeMenu);
    });

    return {
      tagRefs,
      tagsViewStore,
      isActive,
      isAffix,
      closeSelectedTag,
      visible,
      refreshSelectedTag,
      selectedTag,
      closeOthersTags,
      closeAllTags,
      openMenu,
      left,
      top,
      closeMenu,
    };
  },
};
</script>

<style lang="scss" scoped>
.tags-view-container {
  height: var(--v3-tagsview-height);
  width: 100%;
  background-color: var(--v3-header-bg-color);
  box-shadow: 0 0 3px 0 #00000010;
  .tags-view-wrapper {
    .tags-view-item {
      display: inline-block;
      position: relative;
      cursor: pointer;
      height: 26px;
      line-height: 26px;
      border: 1px solid var(--v3-tagsview-tag-border-color);
      border-radius: var(--v3-tagsview-tag-border-radius);
      color: var(--v3-tagsview-tag-text-color);
      background-color: var(--v3-tagsview-tag-bg-color);
      padding: 0 8px;
      font-size: 12px;
      margin-left: 5px;
      margin-top: 4px;
      &:first-of-type {
        margin-left: 5px;
      }
      &:last-of-type {
        margin-right: 5px;
      }
      &.active {
        background-color: var(--v3-tagsview-tag-active-bg-color);
        color: var(--v3-tagsview-tag-active-text-color);
        border-color: var(--v3-tagsview-tag-active-border-color);
        &::before {
          content: "";
          background-color: var(--v3-tagsview-tag-active-before-color);
          display: inline-block;
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: relative;
          margin-right: 2px;
        }
      }
      .el-icon {
        margin: 0 2px;
        vertical-align: middle;
        border-radius: 50%;
        &:hover {
          background-color: var(--v3-tagsview-tag-icon-hover-bg-color);
          color: var(--v3-tagsview-tag-icon-hover-color);
        }
      }
    }
  }
  .contextmenu {
    margin: 0;
    background-color: #fff;
    z-index: 3000;
    position: absolute;
    list-style-type: none;
    padding: 5px 0;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 400;
    color: #333;
    box-shadow: 2px 2px 3px 0 #00000030;
    li {
      margin: 0;
      padding: 7px 16px;
      cursor: pointer;
      &:hover {
        background-color: #eee;
      }
    }
  }
}
</style>
